/*
  File:    Polynomial.cpp
  Purpose: Polynomial class, as well as derivatives.

  Contact: Paul Macklin
           pmacklin@math.uci.edu
		  http://math.uci.edu/~pmacklin
*/

#include <cstdlib>
#include <cmath>
#include <iostream>

using namespace std;

#include "../ImprovedMath.h"
#include "Polynomial.h"

double Polynomial::Evaluate( double input )
{
 double output = coefficients[degree];
 int i=degree-1;
 while( i > -1 )
 {
  output *= input; 
  output += coefficients[i];
  i--;
 }
 return output;
}
 
double Polynomial::operator()( double input )
{ return Evaluate( input ); }

Polynomial::Polynomial()
{
 degree = 0;
 variable = 'x';
 coefficients = new double [degree+1];
 for( int i=0; i <= degree ; i++ )
 { coefficients[i] = 0.0; }
}

Polynomial::Polynomial( int NewDegree )
{
 degree = NewDegree;
 coefficients = new double [degree+1];
 variable = 'x';
 for( int i=0; i <= degree ; i++ )
 { coefficients[i] = 0.0; }
}

Polynomial::~Polynomial()
{
 delete [] coefficients;
}

double Polynomial::norm2( void )
{
 double output = 0.0;
 for( int i= 0 ; i <= degree ; i++ )
 {
  output += square( coefficients[i] );
 }
 return sqrt( output );
}
 
bool Polynomial::SetDegree( int NewDegree )
{
 if( NewDegree < 0 )
 { NewDegree = 0; }
 delete [] coefficients; 
 degree = NewDegree;
 coefficients = new double [degree+1];
 for( int i=0; i <= degree ; i++ )
 { coefficients[i] = 0.0; }
 return true;
}

int Polynomial::GetDegree( void ) const
{
 return degree;
}

bool Polynomial::SetVariable( char input )
{ 
 variable = input;
 return true;
}

char Polynomial::GetVariable( void ) const 
{ return variable; }

bool Polynomial::SetCoefficient( int Term, double Coefficient )
{
 if( Term > degree || Term < 0 )
 { return false; }
 coefficients[Term] = Coefficient;
 return true;
}

double Polynomial::GetCoefficient( int Term ) const
{
 if( Term > degree || Term < 0 )
 { return 0.0; }
 return coefficients[Term];
}

void Polynomial::display( void ) 
{
 int i;
 cout << coefficients[0]; 
 for( i=1 ; i <= degree ; i++ )
 {
  cout << " + " << coefficients[i] << " * " << variable << "^" << i;
  if( !( i % 4 ) )
  { cout << endl; }
 }
 cout << endl;
 return;
}
  
Polynomial Derivative( Polynomial& Input )
{
 if( Input.GetDegree() == 0 )
 { Polynomial Output(0); Output.SetCoefficient(0,0.0); return Output; }

 Polynomial Output(Input.GetDegree()-1);
 Output.SetVariable( Input.GetVariable() );
 
 for( int n=0 ; n <= Output.GetDegree() ; n++ )
 { Output.SetCoefficient(n,  (n+1)*Input.GetCoefficient(n+1)  );   }
 return Output;
}

Polynomial SecondDerivative( Polynomial& Input )
{
 if( Input.GetDegree() <= 1 )
 { Polynomial Output(0); Output.SetCoefficient(0,0.0); return Output; }

 Polynomial Output(Input.GetDegree()-2);
 Output.SetVariable( Input.GetVariable() ); 
 
 for( int n=0 ; n <= Output.GetDegree() ; n++ )
 { Output.SetCoefficient(n,  (n+2)*(n+1)*Input.GetCoefficient(n+2)  );   }
 return Output;
}

Polynomial NthDerivative( Polynomial& Input , int order )
{
 if( Input.GetDegree() <= order-1 )
 { Polynomial Output(0); Output.SetCoefficient(0,0.0); return Output; }

 Polynomial Output(Input.GetDegree()-order);
 Output.SetVariable( Input.GetVariable() ); 
 
 for( int n=0 ; n <= Output.GetDegree() ; n++ )
 { Output.SetCoefficient(n, ( (double) factorial(n+order) )
                            * Input.GetCoefficient(n+order) 
							/ ( (double) factorial(n) )  );   }
 return Output;
}

Polynomial::Polynomial( const Polynomial& Input )
{
// SetDegree( Input.GetDegree() );
 degree = Input.GetDegree();
 coefficients = new double [degree+1];
 
 variable = Input.GetVariable();

 for( int i=0 ; i <= degree ; i++ )
 {
  coefficients[i] = Input.GetCoefficient(i); 
 }
 return;
}

Polynomial& Polynomial::operator=( const Polynomial& Input )
{
// SetDegree( Input.GetDegree() );
 degree = Input.GetDegree();
 coefficients = new double [degree+1];
 variable = Input.GetVariable();

 for( int i=0 ; i <= degree ; i++ )
 {
  coefficients[i] = Input.GetCoefficient(i);
 }

 return *this;
}
